﻿using BackData;
using Domain.DTOs.RBAC;
using Domain.RBAC;
using Infratructure;
using MD5Hash;
using MediatR;
using Microsoft.IdentityModel.Tokens;
using SqlSugar;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Team.API.Applocation.Command;

namespace Team.API.Applocation.Hanldler
{
    public class LoginUserHandler : IRequestHandler<LoginUserCommand, APIResult<UserDTO>>
    {

        private readonly IRepository<Usermodel> userRepository;

        private readonly IRepository<Rolemodel> roleRepository;

        private readonly IRepository<Departmentmodel> depRepository;

        private readonly IRepository<Permissionmodel> permissionRepository;

        private readonly IRepository<Rolepermissionmiddle> rolePermissionRepository;

        /// <summary>
        /// <summary>/// 构造函数
        /// </summary>
        /// <param name="configuration"></param>
        public LoginUserHandler(IRepository<Usermodel> userRepository, IRepository<Rolemodel> roleRepository, IRepository<Departmentmodel> depRepository, IRepository<Permissionmodel> permissionRepository, IRepository<Rolepermissionmiddle> rolePermissionRepository)
        {
            this.userRepository = userRepository;
            this.roleRepository = roleRepository;
            this.depRepository = depRepository;
            this.permissionRepository = permissionRepository;
            this.rolePermissionRepository = rolePermissionRepository;
        }

        public async Task<APIResult<UserDTO>> Handle(LoginUserCommand request, CancellationToken cancellationToken)
        {
            var user = await userRepository.GetAll().Where(x => x.UserName == request.Username).FirstAsync();
            if (user == null)
            {
                return APIResult<UserDTO>.Faile("账号不存在");
            }

            var pass = request.Userpass.GetMD5WithSalt(user.Salt);
            if (pass != user.Password)
            {
                return APIResult<UserDTO>.Faile("账号密码不匹配");
            }

            var role = await roleRepository.GetByIdAsync(user.RoleId);

            var dep = await depRepository.GetByIdAsync(user.DepartmentId);

            // 获取用户权限列表（通过角色权限中间表）
            // 这是异步方法，需要等待执行完成
            var permissions = await GetUserPermissionsAsync(role.Id);

            UserDTO login = new UserDTO()
            {
                Id = user.Id,
                UserCode = user.UserCode,
                UserName = user.UserName,
                RealName = user.RealName,
                RoleId = user.RoleId,
                RoleName = role.RoleName,
                DepartmentId = user.DepartmentId,
                DepartmentName = dep.DepartmentName,
                Phone = user.Phone,
                Email = user.Email,
                Permissions = permissions  // 将权限列表存储到UserDTO中
            };

            return APIResult<UserDTO>.Ok("登录成功", login);

        }

        /// <summary>
        /// 获取用户权限列表（异步方法）
        /// 这个方法通过角色ID，从角色权限中间表获取所有权限，然后构建权限树
        /// </summary>
        /// <param name="roleId">角色ID</param>
        /// <returns>返回权限树列表（只包含顶级权限，子权限在Children中）</returns>
        private async Task<List<PermissionDTO>> GetUserPermissionsAsync(long roleId)
        {
            // 第一步：通过角色ID从角色权限中间表获取所有权限ID
            // 这个查询会找到该角色关联的所有权限ID
            var rolePermissions = await rolePermissionRepository.GetAll()
                .Where(rp => rp.RoleId == roleId && rp.IsDel == false)
                .ToListAsync();

            // 如果角色没有分配任何权限，返回空列表
            if (rolePermissions == null || rolePermissions.Count == 0)
            {
                return new List<PermissionDTO>();
            }

            // 第二步：提取所有权限ID
            // 使用Select方法从角色权限中间表中提取Permissionid字段，得到权限ID列表
            var permissionIds = rolePermissions.Select(rp => rp.PermissionId).ToList();

            // 第三步：根据权限ID列表获取所有权限实体
            // 这里需要获取所有相关的权限，包括：
            // 1. 直接分配给角色的权限
            // 2. 这些权限的父级权限（因为如果只给子权限，父权限也应该显示）
            var allPermissions = await permissionRepository.GetAll()
                .Where(p => p.IsDel == false)
                .ToListAsync();

            // 第四步：构建权限ID集合（包括直接分配的权限和它们的父级权限）
            // 使用HashSet提高查找效率
            HashSet<long> validPermissionIds = new HashSet<long>(permissionIds);

            // 第五步：向上查找父级权限
            // 如果某个权限在权限ID列表中，那么它的所有父级权限也应该包含在内
            foreach (var permissionId in permissionIds)
            {
                // 递归向上查找父级权限
                AddParentPermissions(allPermissions, permissionId, validPermissionIds);
            }

            // 第六步：过滤出有效的权限（只包含在validPermissionIds中的权限）
            var validPermissions = allPermissions
                .Where(p => validPermissionIds.Contains(p.Id))
                .ToList();

            // 第七步：使用递归方法构建权限树
            // 从顶级权限（Parentid == 0）开始，递归构建树形结构
            var permissionTree = BuildPermissionTree(validPermissions, 0);

            return permissionTree;
        }

        /// <summary>
        /// 递归向上查找父级权限
        /// 这个方法会从给定的权限ID开始，向上查找所有父级权限，并将它们添加到集合中
        /// </summary>
        /// <param name="allPermissions">所有权限列表</param>
        /// <param name="permissionId">当前权限ID</param>
        /// <param name="validPermissionIds">有效的权限ID集合（用于存储结果）</param>
        private void AddParentPermissions(List<Permissionmodel> allPermissions, long permissionId, HashSet<long> validPermissionIds)
        {
            // 查找当前权限
            var permission = allPermissions.FirstOrDefault(p => p.Id == permissionId);

            // 如果权限不存在或已经是顶级权限（ParentId == 0），则停止递归
            if (permission == null || permission.ParentId == 0)
            {
                return;
            }

            // 将父级权限ID添加到集合中
            validPermissionIds.Add(permission.ParentId);

            // 递归查找父级权限的父级权限
            AddParentPermissions(allPermissions, permission.ParentId, validPermissionIds);
        }

        /// <summary>
        /// 递归构建权限树
        /// 这个方法将扁平的权限列表转换为树形结构
        /// </summary>
        /// <param name="allPermissions">所有权限列表（扁平结构）</param>
        /// <param name="parentId">父级权限ID，0表示顶级权限</param>
        /// <returns>返回权限树列表（只包含当前层级的权限，子权限在Children中）</returns>
        private List<PermissionDTO> BuildPermissionTree(List<Permissionmodel> allPermissions, long parentId)
        {
            // 第一步：查找所有父级ID等于指定parentId的权限
            // 这些权限是当前层级的权限
            var currentLevelPermissions = allPermissions
                .Where(p => p.ParentId == parentId)
                .ToList();

            // 如果当前层级没有权限，返回空列表
            if (currentLevelPermissions.Count == 0)
            {
                return new List<PermissionDTO>();
            }

            // 第二步：创建当前层级的权限DTO列表
            List<PermissionDTO> result = new List<PermissionDTO>();

            // 第三步：遍历当前层级的每个权限
            foreach (var permission in currentLevelPermissions)
            {
                // 创建权限DTO对象
                var permissionDto = new PermissionDTO
                {
                    Id = permission.Id,                           // 权限的唯一标识
                    PermissionCode = permission.PermissionCode,   // 权限编号
                    PermissionName = permission.PermissionName,   // 权限名称
                    PermissionUrl = permission.PermissionUrl,     // 权限路径
                    ParentId = permission.ParentId,               // 父级权限ID
                    PermissionType = permission.PermissionType,   // 权限类型
                    Icon = permission.Icon,                       // 权限图标
                    Sort = permission.Sort,                       // 排序号
                    Status = permission.Status,                   // 权限状态
                    Children = new List<PermissionDTO>()          // 初始化子权限列表
                };

                // 第四步：递归查找当前权限的子权限
                // 这是递归的核心：对每个权限，查找它的子权限，并构建子树
                var children = BuildPermissionTree(allPermissions, permission.Id);

                // 第五步：将子权限添加到当前权限的Children中
                permissionDto.Children = children;

                // 第六步：将当前权限添加到结果列表中
                result.Add(permissionDto);
            }

            // 第七步：返回当前层级的权限列表
            return result;
        }

        /// <summary>
        /// 生成 JWT Token（令牌）
        /// </summary>
        /// <returns></returns>
        private string CreateTokenString()
        {
            //私钥
            var secretByte = Encoding.UTF8.GetBytes("kdsfldsflkdslkflkdsflkdslfdslkflk");
            // 非对称加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            // 使用256 生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            // 生成Token
            var token = new JwtSecurityToken(
                issuer: "BeiJingBW",
                audience: "BeiJingBW",
                expires: DateTime.Now.AddDays(1), // 一天后过期
                signingCredentials: signingCredentials
            );
            // 生成token 字符串
            var strToken = new JwtSecurityTokenHandler().WriteToken(token);
            return strToken;
        }
    }
}
